//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#ifndef __ELASTOS_THREAD_H__
#define __ELASTOS_THREAD_H__

typedef void (CDECL *threadentry_t)(threadroutine_t, void *);

class CProcess;
class DzTimer;
class ScheduleClass;

class _CThread : public IThread
{
public:
    CARAPI_(PInterface) Probe(REIID riid);
};

class _CThreadContext : public IThreadContext
{
public:
    CARAPI_(PInterface) Probe(REIID riid);
};


class InProcessLinkNode : public ObjectEnumeratorNode
{
public:
    CARAPI_(PInterface) GetObject();
};

#ifdef _DEBUG
#define THREAD_END_MARKER       0x87654321
#endif // _DEBUG

#define MAX_NUMBER_OF_RUOS      MAXIMUM_OWNED_READER_LOCKS

class Thread : public DLinkNode, public _CThread, public _CThreadContext
{
friend bool_t CDECL InitThreads();

public:
    //
    // Interface methods.
    //
    CARAPI_(PInterface) Probe(
        /* [in] */ REIID riid);

    CARAPI_(PInterface) ObjProbe(
        REIID Self_riid,
        REIID riid);

    CARAPI_(UInt32) AddRef(void);

    CARAPI_(UInt32) Release(void);

    CARAPI Aggregate(
        /* [in] */ AggrType aggrType,
        /* [in] */ IInterface* pObject);

    CARAPI GetDomain(
        /* [out] */ IInterface** ppObj);

    CARAPI Start();

    CARAPI Suspend();

    CARAPI Resume();

    CARAPI Join(
        /* [in] */ Millisecond32 timeout,
        /* [out] */ WaitResult *pResult);

    CARAPI Interrupt();

    CARAPI Abort();

    CARAPI SetPriority(
        /* [in] */ ThreadPriority priority);

    CARAPI GetPriority(
        /* [out] */ ThreadPriority * pPriority);

    CARAPI GetId(
        /* [out] */ ThreadId * pTid);

    CARAPI SetName(
        /* [in] */ WString name);

    CARAPI GetName(
        /* [out] */ WStringBuf * name);

    CARAPI GetState(
        /* [out] */ ThreadState * pState);

    CARAPI GetQuitCode(
        /* [out] */ QuitCode * pQuitCode);

    CARAPI GetStartTime(
        /* [out] */ SystemTime * pTime);

    CARAPI GetQuitTime(
        /* [out] */ SystemTime * pTime);

    CARAPI GetProcessorTimes(
        /* [out] */ int * pUserTime,
        /* [out] */ int * pKernelTime);

//IThreadContext
    CARAPI GetContext(
        /* [out] */ ArrayOf<Int32> *pContextArray);

    CARAPI SetContext(
        /* [out] */ const ArrayOf<Int32> &contextArray);

    CARAPI GetUserStackTop(
        /* [out] */ Address *pStackTop);

    CARAPI Quit();

public:
    void * operator new(size_t s);
    void operator delete(void *pv);
    STATIC void ReclaimFreeThreads();

public:
    //
    // Internal methods.
    //

    ECode Initialize(
        threadentry_t threadentry,
        threadroutine_t threadroutine, void *pvParameter,
        ScheduleClass *pScheduleClass, uint_t uSchedulePolicy);

    ECode Initialize(
        CProcess *pOwner, threadroutine_t threadroutine, void *pvParameter,
        ScheduleClass *pScheduleClass, uint_t uSchedulePolicy);

    // only for thread0
    DECL_CODEINIT void Initialize0(virtaddr_t vaKernelStack);

    void SetUserEntry(virtaddr_t vaUserStack, virtaddr_t vaUserEntry);
    void SetKernelEntry(threadroutine_t fnEntry, void *pvArg);

//    void BindTimer(DzTimer *pTimer);
    void CancelBindingTimer();

    void DetachFromSyncObject(SyncObject *pWaitingSyncObject);

    void AddUndoOperation(UndoOperation *pUndoOperation);
    void RemoveUndoOperation(UndoOperation *pUndoOperation);

    bool_t CanAcquireReaderLock();
    void AddReaderUndoOperation(RWLock *pRWLock);
    ReaderUndoOperation *FindReaderUndoOperation(RWLock *pRWLock);
    void RemoveReaderUndoOperation(ReaderUndoOperation *pReaderUndoOperation);

    void UndoAll();

    void IsReaderLockHeld(const RWLock *pRWLock, Boolean *pIsHeld);
    void IsWriterLockHeld(const RWLock *pRWLock, Boolean *pIsHeld);

    bool_t IsRunning() const;
    bool_t IsSleeping() const;
    bool_t IsInterruptibleSleeping() const;

    bool_t IsSuspended() const;
    bool_t IsFinished() const;
    bool_t IsFinishingOrFinished() const;

    void SetEventState(uint_t uState)
    {
#ifdef _DEBUG
        m_uNotifiedEventIndex = MAXIMUM_WAIT_EVENTS; // Invalid index value
#endif
        m_uEventState = uState;
    }

    void SetEventState(uint_t uNotifiedEventIndex, uint_t uState)
    {
        assert(MAXIMUM_WAIT_EVENTS > uNotifiedEventIndex);
        m_uNotifiedEventIndex = uNotifiedEventIndex;
        m_uEventState = uState;
    }

    uint_t GetNotifiedEventIndex() const
    {
        assert(MAXIMUM_WAIT_EVENTS > m_uNotifiedEventIndex);
        return m_uNotifiedEventIndex;
    }

    uint_t GetEventState() const        { return m_uEventState; }

    ECode ReadyToWakeUp();
    ECode ReadyToWakeUpByIsr();

//    ECode WakeUp(bool_t bDirectSchedule = TRUE);
    void WakeUpOnTimeout();

    void WillToInheritPriority(const Thread *pThread);
    void WaiveInheritedPriority(register bool_t bSchedule = TRUE);

    INLINE void AddOwnedSyncObject(SyncObject *pOwnedSyncObject);
    INLINE void RemoveOwnedSyncObject(SyncObject *pOwnedSyncObject);

    void * ReallocBuffer(size_t size);

    void ReadyToStart();

    ECode Abort(CProcess *pOwner);

    void Uninitialize()
    {
        ReallocBuffer(0);
    }

    virtual ~Thread() {}

private:
    void CommonInitialize();

    ECode CommonInitialize2(
        ScheduleClass *pScheduleClass, uint_t uSchedulePolicy);

    INLINE void InheritPriority(const Thread *pThread);
    INLINE void RestorePriority();

public:
    PreemptionLock          m_lock;

    uint_t                  m_uState;

    uint_t                  m_uNestedSuspend;

    bool_t                  m_bPendingInterrupt;
    bool_t                  m_bInterrupted;

    DzTimer                 *m_pBindingTimer;

    SyncObject              *m_pWaitingSyncObject;

    DLinkNode               m_undoOperationListHead;

    uint_t                  m_uNotifiedEventIndex;
    uint_t                  m_uEventState;

    bool_t                  m_bFinishing;

    KMutex                  m_activeLock;

    ScheduleClass           *m_pScheduleClass;
    uint_t                  m_uSchedulePolicy;

    uint_t                  m_uBasePriority;
    uint_t                  m_uDynamicPriority;

    int                     m_nTimeQuota;

    bool_t                  m_bInherit;

    ScheduleClass           *m_pEffectiveScheduleClass;
    uint_t                  m_uEffectiveSchedulePolicy;

    uint_t                  m_uEffectiveBasePriority;
    uint_t                  m_uEffectiveDynamicPriority;

    int                     m_nEffectiveTimeQuota;

    DLinkNode               m_ownedSyncObjectListHead;

    uint_t                  m_uReadyStartTick;

    bool_t                  m_bNeedReschedule;

    virtaddr_t              m_vaKernelStack;
    virtaddr_t              m_vaKernelStackPtr;

    InProcessLinkNode       m_inProcLink;
    bool_t                  m_bHasUserEntry;
    threadroutine_t         m_fnKernelEntry;
    void                    *m_pvKernelEntryArg;

    uint_t                  m_uUserStackBase;


    Int32                   m_exitCode;
    uint_t                  m_uPoolThreadState;
    bool_t                  m_isDllProcDetachThd;
    DzEvent                 m_startEvent;
    DzEvent                 m_joinEvent;

    SystemTime              m_startTime;
    SystemTime              m_finishTime;

    uint_t                  m_uUserProcessorTicks;
    uint_t                  m_uPrivilegedProcessorTicks;

    CProcess*               m_pOwner;

    ThreadHContext          m_hcontext;

    // the three para as below just for a CAR interface function call
    void                    *m_pBuffer;  // size is m_uBufferSize
    UInt32                  m_uBufferSize;
    Thread*                 m_pClientThread;
    void                    *m_pvFields[TF_MINIMUM_AVAILABLE];
    wchar_t                 m_wszName[MAXIMUM_THREAD_NAME_LENGTH];

public:
    DLinkNode               m_unusedReaderUndoOperationList;
    ReaderUndoOperation     m_readerUndoOperations[MAX_NUMBER_OF_RUOS];

#ifdef _DEBUG
    UInt8                   m_u8Reserved[0x100];
    UInt32                  m_uEndMarker;
#endif // _DEBUG

    // IMPORTANT: Do not place members here.

private:
    STATIC PreemptionLock   s_freeListLock;
    STATIC DLinkNode        s_freeListHead;
    STATIC uint_t           s_uNumberOfFreeThreads;
};

INLINE PInterface _CThread::Probe(REIID riid)
{
    return (((Thread *)(_CThread *)this)-> \
            ObjProbe(EIID_IThread, riid));
}

INLINE PInterface _CThreadContext::Probe(REIID riid)
{
    return (((Thread *)(_CThreadContext *)this)-> \
            ObjProbe(EIID_IThreadContext, riid));
}

INLINE bool_t Thread::IsRunning() const
{
    return ThreadState_Running == m_uState;
}

INLINE bool_t Thread::IsSleeping() const
{
    return m_uState & ThreadState_Sleeping;
}

INLINE bool_t Thread::IsInterruptibleSleeping() const
{
    return (m_uState & ThreadState_InterruptibleSleeping)
            == ThreadState_InterruptibleSleeping;
}

INLINE bool_t Thread::IsSuspended() const
{
    return m_uState & ThreadState_Suspended;
}

INLINE bool_t Thread::IsFinished() const
{
    return ThreadState_Finished == m_uState;
}

INLINE bool_t Thread::IsFinishingOrFinished() const
{
    return m_bFinishing || IsFinished();
}

INLINE void Thread::SetKernelEntry(threadroutine_t fnEntry, void *pvArg)
{
    m_fnKernelEntry = fnEntry;
    m_pvKernelEntryArg = pvArg;
}

INLINE void Thread::AddOwnedSyncObject(SyncObject *pOwnedSyncObject)
{
    assert(pOwnedSyncObject);
    assert(pOwnedSyncObject->m_pOwner == this);

    m_lock.Lock();
    m_ownedSyncObjectListHead.InsertLast(pOwnedSyncObject);
    m_lock.Unlock();
}

INLINE void Thread::RemoveOwnedSyncObject(SyncObject *pOwnedSyncObject)
{
    assert(pOwnedSyncObject);
    assert(pOwnedSyncObject->m_pOwner == this);

    m_lock.Lock();
    pOwnedSyncObject->Detach();
    m_lock.Unlock();
}

EXTERN Thread *GetThread0();

// IMPORTANT: if the current thread is a non-user thread,
//      then GetCurrentProcess() return NULL
INLINE CProcess *GetCurrentProcess()
{
    return GetCurrentThread()->m_pOwner;
}

EXTERN Thread *CreateSystemThread(
        threadroutine_t threadroutine, void *pvParameter,
        ScheduleClass *pScheduleClass, uint_t uSchedulePolicy);

EXTERN Thread *CreateThread(
        CProcess *pOwner, threadroutine_t threadroutine, void *pvParameter,
        ScheduleClass *pScheduleClass, uint_t uSchedulePolicy);

INLINE bool_t ClearPendingInterrupt()
{
    return InterlockedExchange(
        &GetCurrentThread()->m_bPendingInterrupt, FALSE);
}

INLINE bool_t ClearInterrupted()
{
    return InterlockedExchange(
        &GetCurrentThread()->m_bInterrupted, FALSE);
}

EXTERN void UninterruptibleSleep();
EXTERN void UninterruptibleSleep(uint_t uTicks);

EXTERN void ReadyToUninterruptibleSleepOn(
        SyncObject *pWaitingSyncObject = NULL, DzTimer *pBindingTimer = NULL);

EXTERN void ReadyToSleepOn(
        SyncObject *pWaitingSyncObject, DzTimer *pBindingTimer,
        WaitResult *pResult);

EXTERN void ExitThread(CProcess *pOwner);

EXTERN void UpdateCurrentThreadTime(uint_t uTicks, bool_t bUserMode);

INLINE void WaiveInheritedPriority(register bool_t bSchedule = TRUE)
{
    GetCurrentThread()->WaiveInheritedPriority(bSchedule);
}

INLINE bool_t CanAcquireReaderLock()
{
    return GetCurrentThread()->CanAcquireReaderLock();
}

EXTERN PVoid STDCALL AddPeriodicTask(
        int nTime, threadroutine_t fnTaskRoutine, void *pvArg);

EXTERN void STDCALL CancelPeriodicTask(PVoid taskHandle);

EXTERN void StopPeriodicTasks();

#endif //__ELASTOS_THREAD_H__
